using System;
using System.Resources;
using System.Drawing;
using System.Collections;
using System.Reflection;
using System.ComponentModel;
using System.Text;
using System.IO;
using Microsoft.BizTalk.Message.Interop;
using Microsoft.BizTalk.Component.Interop;
using System.Xml;
using Microsoft.Samples.BizTalk.Pipelines.CustomComponent;

namespace HIPAA_Pipelines
{

    [ComponentCategory(CategoryTypes.CATID_PipelineComponent)]
    [ComponentCategory(CategoryTypes.CATID_Any)]
    [ComponentCategory(CategoryTypes.CATID_Validate)]
    [System.Runtime.InteropServices.Guid("9d0e4103-4cce-4536-83fa-4a5040674ad6")]
    public class Availity_HTTP_Send_Component :
        IBaseComponent,
        Microsoft.BizTalk.Component.Interop.IComponent,
        Microsoft.BizTalk.Component.Interop.IPersistPropertyBag,
        IComponentUI
    {
        static ResourceManager resManager = new ResourceManager("HIPAA_Pipelines.Availity_HTTP_Send_Component", Assembly.GetExecutingAssembly());


        // Component information
        #region IBaseComponent
        public string Name { get { return "Availity HTTP Send Component"; } }
        public string Version { get { return "1.0"; } }
        public string Description { get { return "Constructs the valid Availity HTTP Message"; } }
        public IntPtr Icon
        {
            get
            {
                return new System.IntPtr();
            }
        }
        public System.Collections.IEnumerator Validate(object projectSystem)
        {
            return null;
        }

        #endregion

        private string _TranCode;
        [
        DisplayName("Transaction type (270,276 or 278)"),
        Description(@"Values:270 0r 276 or 278")
        ]
        public string A_TranCode
        {
            get { return _TranCode; }
            set { _TranCode = value; }
        }
        private string _messageFormat;
        [
        DisplayName("Message Format (X12)"),
        Description(@"Values:X12")
        ]
        public string A_MessageFormat
        {
            get { return _messageFormat; }
            set { _messageFormat = value; }
        }
        
        //This should pull directly from the message body as a context property
        private string _receiver;
        [
        DisplayName("Message Receiver (BCBSF, Humana etc..)"),
        Description(@"Values:Valid valude in the BtB specification.")
        ]
        public string A_Receiver
        {
            get { return _receiver; }
            set { _receiver = value; }
        }

        private string _receiverType;
        [
        DisplayName("Message Receiver Type (Static, Dynamic)"),
        Description(@"Values:Static or Dynamic.  Static is entered in the Receiver Field, Dynamic pulls from the outbound message.")
        ]
        public string A_ReceiverType
        {
            get { return _receiverType; }
            set { _receiverType = value; }
        }

        private string _sender;
        [
        DisplayName("Message Sender (Availity Assigned Sender ID)"),
        Description(@"Values:35 character string value")
        ]
        public string A_Sender
        {
            get { return _sender; }
            set { _sender = value; }
        }

        private string _providerOfficeNbr;
        [
        DisplayName("Provider Office Number"),
        Description(@"3rd party identifier requesting the transaction.")
        ]
        public string A_ProviderOfficeNbr
        {
            get { return _providerOfficeNbr; }
            set { _providerOfficeNbr = value; }
        }

        #region IPersistPropertyBag Members

        public void InitNew()
        {
        }

        public void GetClassID(out Guid classID)
        {
            classID = new Guid("48BEC85A-20EE-40ad-BFD0-319B59A0DDBC");
        }

        public void Load(IPropertyBag propertyBag, int errorLog)
        {
            string val = (string)ReadPropertyBag(propertyBag, "A_TranCode");
            if (val != null) A_TranCode = val;

            val = (string)ReadPropertyBag(propertyBag, "A_MessageFormat");
            if (val != null) A_MessageFormat = val;

            val = (string)ReadPropertyBag(propertyBag, "A_Receiver");
            if (val != null) A_Receiver = val;

            val = (string)ReadPropertyBag(propertyBag, "A_ReceiverType");
            if (val != null) A_ReceiverType = val;

            val = (string)ReadPropertyBag(propertyBag, "A_Sender");
            if (val != null) A_Sender = val;

            val = (string)ReadPropertyBag(propertyBag, "A_ProviderOfficeNbr");
            if (val != null) A_ProviderOfficeNbr = val;

        }
        public void Save(IPropertyBag propertyBag, bool clearDirty, bool saveAllProperties)
        {
            object val = (object)A_TranCode;
            WritePropertyBag(propertyBag, "A_TranCode", val);

            val = (object)A_MessageFormat;
            WritePropertyBag(propertyBag, "A_MessageFormat", val);

            val = (object)A_Receiver;
            WritePropertyBag(propertyBag, "A_Receiver", val);

            val = (object)A_ReceiverType;
            WritePropertyBag(propertyBag, "A_ReceiverType", val);

            val = (object)A_Sender;
            WritePropertyBag(propertyBag, "A_Sender", val);

            val = (object)A_ProviderOfficeNbr;
            WritePropertyBag(propertyBag, "A_ProviderOfficeNbr", val);

        }

        #endregion

        #region IComponent Members
        public IBaseMessage Execute(IPipelineContext pContext, IBaseMessage pInMsg)
        {
            IBaseMessageContext context = pInMsg.Context;

            //Get the Message type and PayerID from the context
            string Message_ST01 = context.Read("ST01", "http://schemas.microsoft.com/Edi/PropertySchema") as string;
            
            //PayerID context should have been set from the Outbound Router orchestration.
            //This uses the CustomMessageContextSchema from the HIPA Schemas project.
            //This approach is more flexible then just promoting PayerID from the original Schema.
            string Payer_ID = context.Read("PayerID", "http://HIPAA_Schemas.CustomMessageContextSchema") as string;
            
            //ISA Segment Information.  Since the EDI variables do not show all ISA segment this is used to set the unique transactionID
            //Keep in mind that the EDI Assembler will create a new ISA segment with new control numbers.
            //We are going to keep the Original ISA Segment information and use the BAM Correlation Tables to determine which original ISA is which tracking number
            //If You want unique TransactionID's we would need to parse the pInMsgBody and pull it out.
            string ISASegment = context.Read("ISA_Segment", "http://schemas.microsoft.com/Edi/PropertySchema") as string;
            HeadersISA originalHeaderISA;
            string SegmentSeparator;
            originalHeaderISA = MessageEnrichmentLibrary.EDIHeaders.ParseX12ISAHeader(ISASegment, out SegmentSeparator);
            
            //Try to read in the new ISA and GS information that was passed by the EDI Assembler
            TextReader _rdr = new System.IO.StreamReader(pInMsg.BodyPart.GetOriginalDataStream());
            string NewEDIDocument = _rdr.ReadToEnd().ToString();

            //Parse out the EDI Message.  The EDI Assembler does not reset the ISA and GSSegment Context properties
            //We have to read the document in and work from there to recreate the EDI Header information
            //Possibly expensive operation here by reading in a whole document
            char _elementSeparator = '~';
            string[] _splittedInput = NewEDIDocument.Trim('\r', '\n').Split(_elementSeparator);
            string newISAString = _splittedInput[0];
            string newGSString = _splittedInput[1];
            HeadersISA newHeaderISA;
            HeadersGS newHeaderGS;           
            newHeaderISA = MessageEnrichmentLibrary.EDIHeaders.ParseX12ISAHeader(newISAString, out SegmentSeparator);
            newHeaderGS = MessageEnrichmentLibrary.EDIHeaders.ParseX12GSHeader(newGSString, SegmentSeparator);

            if (A_MessageFormat == null | A_Receiver == null | A_Sender == null | A_ReceiverType == null | A_ProviderOfficeNbr == null)
            {
                throw new Exception("The Availity_HTTP_Send Pipeline determined there are missing configuration values that are to be set on the pipeline within the BizTalk administration console.");
            }

            //Build new HTTP Message for Availity
            StringBuilder _bldr = new StringBuilder();
            _bldr.Append("<ENVELOPE><HEADER>");
            _bldr.Append("<TranCode>" + Message_ST01 + "</TranCode>");
            _bldr.Append("<MessageFormat>" + A_MessageFormat + "</MessageFormat>");
            _bldr.Append("<Sender>" + A_Sender + "</Sender>");

            if (A_ReceiverType.ToLower() == "dynamic")
            {
                _bldr.Append("<Receiver>" + Payer_ID + "</Receiver>");
            }
            else
            {
                _bldr.Append("<Receiver>" + A_Receiver + "</Receiver>");
            }

            //Session ID is not required
            _bldr.Append("<Session></Session>");
            _bldr.Append("<ProviderOfficeNbr>" + A_ProviderOfficeNbr + "</ProviderOfficeNbr>");
            
            //You could use the original ISA13 value or something unique like the new ISA13 value

            // This value is used to track back the request through availity's systems  (Original ISA13 (ICN) Value)
            // _bldr.Append("<ProviderTransID>" + originalHeaderISA.ISA13 + "</ProviderTransID>");
            
            // This value is used to track back the request through availity's systems (New unique ISA13 (ICN) Value)
            _bldr.Append("<ProviderTransID>" + newHeaderISA.ISA13 + "</ProviderTransID>");

            _bldr.Append("</HEADER>");
            _bldr.Append("<BODY>");

            //Read the entire EDI Message into the body segment
            _bldr.Append(NewEDIDocument);

            _bldr.Append("</BODY>");
            _bldr.Append("</ENVELOPE>");

            
            MemoryStream _stream = new MemoryStream(Encoding.ASCII.GetBytes(_bldr.ToString()));
            //Set the position to the beginning
            _stream.Position = 0;

            pInMsg.BodyPart.Data = _stream;
            
            pContext.ResourceTracker.AddResource(pInMsg.BodyPart.Data);
            
            //Close the original datastream
            _rdr.Close();

            //Set the keep alives to false - from article:http://support.microsoft.com/default.aspx/kb/924638 
            pInMsg.Context.Write("KeepAlive", "http://schemas.microsoft.com/BizTalk/2003/http-properties", false);
            
            return pInMsg;
        }
            
        
        #endregion
        #region Helper Methods

        /// <summary>
        /// Reads property value from property bag.
        /// </summary>
        /// <param name="pb">Property bag.</param>
        /// <param name="propName">Name of property.</param>
        /// <returns>Value of the property.</returns>
        private static object ReadPropertyBag(Microsoft.BizTalk.Component.Interop.IPropertyBag pb, string propName)
        {
            object val = null;
            try
            {
                pb.Read(propName, out val, 0);
            }

            catch (ArgumentException)
            {
                return val;
            }
            catch (Exception ex)
            {
                throw new ApplicationException(ex.Message);
            }
            return val;
        }

        /// <summary>
        /// Writes property values into a property bag.
        /// </summary>
        /// <param name="pb">Property bag.</param>
        /// <param name="propName">Name of property.</param>
        /// <param name="val">Value of property.</param>
        private static void WritePropertyBag(Microsoft.BizTalk.Component.Interop.IPropertyBag pb, string propName, object val)
        {
            try
            {
                pb.Write(propName, ref val);
            }
            catch (Exception ex)
            {
                throw new ApplicationException(ex.Message);
            }
        }
        #endregion
    }
}

